#ifndef TEST
#include <emscripten/emscripten.h>
#endif

#define TRUE 1
#define FALSE 0

#ifdef __cplusplus
extern "C" {
#endif

/**
 * 将buffer中的前4个字节，转为大端模式，并且返回Int值
 */
int transform4ByteIntToBigEndian(char * buffer){
	char bigEndian[4];
	bigEndian[0] = buffer[3];
	bigEndian[1] = buffer[2];
	bigEndian[2] = buffer[1];
	bigEndian[3] = buffer[0];
	return ((int *)bigEndian)[0];
}

/**
 * 对比源字符串与目标字符串 类型是否相同
 * 类型只占前4字节，因此对比前4个字节
 * @param type 源字符串
 * @param aimType 目标匹配字符串
 * @return @value{1} 类型相同 @value{0} 类型不同
 */
int compareType(char * type, char * aimType){
	int i = 0, isSame = TRUE;// Regard As True For The Beginning
	for(i = 0;i<4;i++){
		if(aimType[i] != type[i]){
			isSame = FALSE;// While Not The Same Then Set False and Break Compare
			break;
		}
	}
	return isSame;
}

/**
 * 在MP4同一层盒子层级之中，查找目标类型的盒子
 * @param buffer 指向的盒子的起始地址
 * @param boxlen 从当前位置到本层盒子结束的长度
 * @param aimType 目标盒子类型 长度始终为4个字节
 * @return 目标盒子的起始地址 若未找到返回NotFound字符串
 */
char * findBoxAtLayer(char * buffer, long boxlen, char * aimType){
	char * currentBufferStart = buffer;
	do{
		int subBoxLen = transform4ByteIntToBigEndian(currentBufferStart);
		char * subBoxType = currentBufferStart + 4;
		if(compareType(subBoxType, aimType)){
			return currentBufferStart;
		}
		currentBufferStart = currentBufferStart + subBoxLen;
	}while(currentBufferStart < buffer + boxlen);
	return "NotFound\0";
}

/**
 * 从trak盒子开始，找到帧数
 * @param trak 指向的Trak盒子的起始地址+8
 * @param trakLen 从当前位置到本层盒子结束的长度
 * @return 帧数
 */
int getFrameCountFromTrack(char * trak, int trakLen){
	char * mdia = findBoxAtLayer(trak + 8, trakLen - 8, "mdia");
	int mdiaLen = transform4ByteIntToBigEndian(mdia);
	char * minf = findBoxAtLayer(mdia + 8, mdiaLen - 8, "minf");
	int minfLen = transform4ByteIntToBigEndian(minf);
	char * stbl = findBoxAtLayer(minf + 8, minfLen - 8, "stbl");
	int stblLen = transform4ByteIntToBigEndian(stbl);
	char * stsz = findBoxAtLayer(stbl + 8, stblLen - 8, "stsz");
	char * count = stsz + 16;
	return transform4ByteIntToBigEndian(count);
}

/**
 * 从moov盒子开始，找到帧数
 * @param buffer 指向的Trak盒子的起始地址+8
 * @param bufferSize 从当前位置到本层盒子结束的长度
 * @return 帧数
 */
int findFirstVideMediaStszBoxAtLayer(char * buffer, int bufferSize){
	char * bufferStart = buffer;
	int curBufferSize = bufferSize;
	char * trak;
	int trakLen;
	do{
		trak = findBoxAtLayer(bufferStart, curBufferSize, "trak");
		trakLen = transform4ByteIntToBigEndian(trak);
		char * mdia = findBoxAtLayer(trak+8, trakLen -8, "mdia");
		int mdiaLen = transform4ByteIntToBigEndian(mdia);
		char * hdlr = findBoxAtLayer(mdia+8, mdiaLen -8, "hdlr");
		char * mediaType = hdlr + 16;
		if(compareType(mediaType, "vide")){
			break;
		}else{
			bufferStart = trak + trakLen;
		}
	}while(bufferStart <buffer + bufferSize);
	int result = getFrameCountFromTrack(trak, trakLen);
	return result;
}

/**
 * 从mp4文件开始，找到帧数
 * @param buffer 文件内容
 * @param boxlen 文件大小
 * @return 帧数
 */
#ifndef TEST
EMSCRIPTEN_KEEPALIVE
#endif
int getFrameCount (char * buffer, long boxlen){
	char * moov = findBoxAtLayer(buffer, boxlen, "moov");
	int moovLen =  transform4ByteIntToBigEndian(moov);
	int frameCount = findFirstVideMediaStszBoxAtLayer(moov+8, moovLen - 8);// Container BoX + 8 
	return frameCount;
}

#ifdef __cplusplus
}
#endif

//测试方法
//int main(){
//	/*Read byte Array From File*/
//	FILE *fileptr;  // File Pointer
//	char *buffer;   // File Content Byte Array
//	long filelen;	// File Length
//	
//	fileptr = fopen("./1.mp4", "rb");     // Open the file in binary mode
//	fseek(fileptr, 0, SEEK_END);          // Jump to the end of the file
//	filelen = ftell(fileptr);             // Get the current byte offset in the file
//	rewind(fileptr);                      // Jump back to the beginning of the file
//	
//	buffer = (char *)malloc(filelen * sizeof(char)); // Enough memory for the file
//	fread(buffer, filelen, 1, fileptr);              // Read in the entire file
//	fclose(fileptr);                                 // Close the file
//	/*Get Frame Rate*/
//	int frameCount = 0;
//	frameCount = getFrameCount(buffer,filelen);
//	printf("FrameCount: %d", frameCount);
//	return 0;
//}

//EMSCRIPTEN_BINDINGS(my_module) {
//  emscripten::function("getFrameCount", &getFrameCount);
//}



